<template>
	<div ref="container">
		<div style="position: absolute; z-index: 10" class="flex-center w100 h100" v-show="loading">
			<dv-decoration :scale="2">
				<span class="fw" style="font-size: 30px"> {{ percentComplete }}% </span>
			</dv-decoration>
		</div>
		<div class="geo-box" style="right: 10px; bottom: 10px">
			<span>经度：{{ long_lat.x }}</span>
			<span>纬度：{{ long_lat.z }}</span>
			<span>海拔：{{ long_lat.y }}</span>
		</div>
	</div>
</template>

<script setup name="tunnelling">
// 引入全局资源
import plugin from '@/utils/plugin'
import labelDemo from './labelDemo.vue'
import { DBUtil } from '@u/indexedDB'
import { throttle } from '@u/util'
import {
	useResizeObserver,
	THREE,
	GLTFloaderFn,
	clock,
	textureLoader,
	MapControls,
	CSS2DObject,
	rendererFn,
	labelRendererFn,
	mixersFn
} from '@u/threeMinx'

const props = defineProps({
	type: {
		type: Number
	}
})

// 初始化场景
let container = shallowRef(null), // 模型渲染的Demo节点
	loading = ref(false), // loading
	percentComplete = ref(0), // 进度
	renderer, // 渲染器
	scene = new THREE.Scene(), // 场景
	camera, // 相机
	controls, // 控制器
	labelRenderer, // 标签渲染器
	width, // 组件宽高
	height

useResizeObserver(container, (entries) => {
	width = entries[0].contentRect.width
	height = entries[0].contentRect.height
	camera.aspect = width / height
	camera.updateProjectionMatrix()
	renderer.setSize(width, height)
	labelRenderer.setSize(width, height)
})
// 初始化生命周期
onMounted(() => {
	loading.value = true
	init()
})
onBeforeUnmount(() => {
	cancelAnimationFrame(requestAnimationFrameIndex)
	// 释放显存
	renderer?.dispose()
	// 释放内存
	scene.clear()
	container = null
	scene = null
	labelRenderer = null
})

function init() {
	// 场景
	scene = new THREE.Scene()
	const background = textureLoader.load(`${import.meta.env.VITE_APP_BASE_BASE || '/'}model/blue2.jpg`)
	background.colorSpace = THREE.SRGBColorSpace
	scene.background = background

	// 相机
	camera = new THREE.PerspectiveCamera(45, container.value.offsetWidth / container.value.offsetHeight, 1, 2000)
	camera.position.set(109.63564910104216, 86.72574213762547, 96.25213350271133)
	scene.add(camera)

	renderer = rendererFn(container)
	labelRenderer = labelRendererFn(container, false)

	// 控制器
	controls = new MapControls(camera, renderer.domElement)
	controls.target.set(110.48293056262132, -50.336801686323525, -3.7927571043980493)
	controls.minPolarAngle = 0
	controls.maxPolarAngle = Math.PI / 2

	// 加载器
	loaderFn()
}
let model,
	mixer,
	centerPoint = [117.076481, 0, 31.660061]

function loaderFn() {
	new DBUtil().get(`${import.meta.env.VITE_APP_BASE_BASE || '/'}model/巷道综采面.glb`).then((blob) => {
		let url = URL.createObjectURL(blob)
		GLTFloaderFn.load(
			url,
			function (object) {
				loading.value = false
				model = object.scene
				model.position.set(...centerPoint)
				loadPlan(model.position)
				scene.add(model)
				// 添加label
				scene.add(objLabel)
				labelFn()
				// 灯光
				lights()
				//动画
				mixer = mixersFn(object)
				// 渲染器
				render()
			},
			function (xhr) {
				if (xhr.lengthComputable) percentComplete.value = Math.round((xhr.loaded / xhr.total) * 100, 2)
			}
		)
	})
}

// 添加label逻辑
let labelData = ref([
	[
		{
			title: '一氧化碳浓度',
			name: '一氧化碳',
			val: '20',
			unit: '%',
			img: '../assets/img/label/co.png',
			position: [99.1077263429123, 0, -10.28176099837259]
		},
		{
			title: '一氧化碳浓度',
			name: '一氧化碳',
			val: '30',
			unit: '%',
			img: '../assets/img/label/co.png',
			position: [110.60365415557996, 0, 40.15225244267442]
		},
		{
			title: '二氧化碳浓度',
			name: '二氧化碳',
			val: '30',
			unit: '%',
			img: '../assets/img/label/co2.png',
			position: [109.38091418508517, 0.24890132993459702, 35.813256459587826]
		},
		{
			img: '../assets/img/label/co2.png',
			position: [104.86692288089702, 0.24890132993459702, 38.91992184507059]
		},
		{
			img: '../assets/img/label/ch4.png',
			position: [100.3066578978087, 0.24890132993459702, 46.153378835018145]
		},
		{
			img: '../assets/img/label/o2.png',
			position: [95.4533682948091, 0.24890132993459702, 52.292816076431386]
		},
		{
			img: '../assets/img/label/smoke.png',
			position: [1120.48855239641689, 0.24890132993461123, 52.2581985014087]
		},
		{
			img: '../assets/img/label/windSpeed.png',
			position: [112.263717814301, 0.00813946086616113, 32.102418696778855]
		}
	],
	[
		{
			img: '../assets/img/label/waterLevel.png',
			position: [109.38091418508517, 0.24890132993459702, 35.813256459587826]
		},
		{
			img: '../assets/img/label/waterLevel.png',
			position: [104.86692288089702, 0.24890132993459702, 38.91992184507059]
		}
	],
	[
		{
			img: '../assets/img/label/temperature.png',
			position: [108.63210836157958, 0.007512023720328109, 32.183433168254034]
		},
		{
			img: '../assets/img/label/temperature.png',
			position: [110.46978207136983, 0.00631549900405215, 31.68355181851937]
		}
	],
	[
		{
			img: '../assets/img/label/smoke.png',
			position: [108.63210836157958, 0.007512023720328109, 32.183433168254034]
		},
		{
			img: '../assets/img/label/smoke.png',
			position: [110.46978207136983, 0.00631549900405215, 31.68355181851937]
		}
	],
	[
		{
			img: '../assets/img/label/co2.png',
			position: [104.86692288089702, 0.24890132993459702, 38.91992184507059]
		},
		{
			img: '../assets/img/label/ch4.png',
			position: [100.3066578978087, 0.24890132993459702, 46.153378835018145]
		},
		{
			img: '../assets/img/label/o2.png',
			position: [95.4533682948091, 0.24890132993459702, 52.292816076431386]
		}
	],
	[
		{
			img: '../assets/img/label/smoke.png',
			position: [112.48855239641689, 0.24890132993461123, 52.2581985014087]
		},
		{
			img: '../assets/img/label/windSpeed.png',
			position: [112.263717814301, 0.00813946086616113, 32.102418696778855]
		}
	]
])

let objLabel = new THREE.Group()
function labelFn() {
	objLabel.clear()
	labelData.value.forEach((arr, i) => {
		arr?.forEach((item) => {
			const dom = createApp(labelDemo, {
				data: item,
				callBack: function () {
					console.log(item)
				}
			})
				.use(plugin)
				.mount(document.createElement('div')).$el
			const pointLabel = new CSS2DObject(dom)
			pointLabel.position.set(...item?.position)
			pointLabel.center = new THREE.Vector2(0.5, 1)
			pointLabel.visibleVal = i
			pointLabel.visible = props.type == i
			objLabel.add(pointLabel)
		})
	})
}
watch(
	() => props.type,
	(val) => typeFn(val)
)
function typeFn(val) {
	objLabel.children?.forEach((item, i) => {
		item.visible = val == item.visibleVal
	})
}
/**
 * @description 构建平面
 */
let plane
function loadPlan({ x, y, z }) {
	// 创建平面
	plane = new THREE.Mesh(
		new THREE.PlaneGeometry(1000, 1000),
		new THREE.MeshLambertMaterial({
			color: 0xffffff,
			side: THREE.DoubleSide,
			opacity: 0,
			transparent: true
		})
	)
	// 旋转放平
	plane.rotation.x = 0.5 * Math.PI
	plane.position.set(x, y, z)
	scene.add(plane)

	renderer.domElement.addEventListener(
		'mousedown',
		(e) => {
			if (e.button == 2) modelOnClick(e, [plane, model], true)
		},
		false
	)
	renderer.domElement.addEventListener(
		'mousemove',
		(e) => {
			throttle(modelOnClick(e, [plane, model], false))
		},
		false
	)
}

// 鼠标右键点击设置控制器中心坐标
const raycaster = new THREE.Raycaster()
let long_lat = ref({
	x: centerPoint[0].toFixed(4),
	y: centerPoint[1].toFixed(4),
	z: centerPoint[2].toFixed(4)
})
function modelOnClick(e, object, mousedown) {
	const { left: left, top: top, width: width, height: height } = renderer.domElement.getBoundingClientRect()

	const mouse = new THREE.Vector2(((e.clientX - left) / width) * 2 - 1, -((e.clientY - top) / height) * 2 + 1)

	raycaster.setFromCamera(mouse, camera)

	const intersects = raycaster.intersectObjects(object)

	if (intersects.length <= 0) {
		// controls.target.set(object.position.x, object.position.y, object.position.z);
	} else {
		const { x, y, z } = intersects[0].point
		long_lat.value = { x: x.toFixed(4), y: y.toFixed(4), z: z.toFixed(4) }
		if (mousedown) console.log(intersects[0].point)
		// controls.target.set(intersects[0].point.x, intersects[0].point.y, intersects[0].point.z);
	}
}

/**
 * 灯光
 */
function lights() {
	// 自然光
	scene.add(new THREE.AmbientLight('#ffffff', 0.8))
}

// 渲染逻辑
let requestAnimationFrameIndex
function render() {
	// label渲染器
	labelRenderer?.render(scene, camera)
	controls.update()
	// 运行动画
	mixer.update(clock.getDelta())
	renderer?.render(scene, camera)
	requestAnimationFrameIndex = requestAnimationFrame(render)
}
</script>

<style lang="scss" scoped>
.geo-box {
	position: absolute;
	background-color: rgba(0, 128, 255, 0.5);
	color: #ffffff;
	font-weight: 500;
	border-radius: 1px;
	padding: 4px 8px;
	span {
		margin-right: 8px;
	}
}
</style>
